package vulnerability

import (
	"fmt"
	"strings"

	"github.com/anchore/grype/grype/pkg"
	"github.com/anchore/grype/internal"
	"github.com/anchore/syft/syft/distro"
	syftPkg "github.com/anchore/syft/syft/pkg"
)

type namer func(p pkg.Package) []string

func defaultNamer(p pkg.Package) []string {
	return []string{p.Name}
}

func githubJavaNamer(p pkg.Package) []string {
	names := internal.NewStringSet()

	// all github advisories are stored by "<group-name>:<artifact-name>"
	if metadata, ok := p.Metadata.(pkg.JavaMetadata); ok {
		if metadata.PomGroupID != "" {
			if metadata.PomArtifactID != "" {
				names.Add(fmt.Sprintf("%s:%s", metadata.PomGroupID, metadata.PomArtifactID))
			}
			if metadata.ManifestName != "" {
				names.Add(fmt.Sprintf("%s:%s", metadata.PomGroupID, metadata.ManifestName))
			}
		}
	}

	return names.ToSlice()
}

// TODO: expand with namer mapping to be more generic?
func distroNamespace(d distro.Distro) string {
	// TODO: can we drive this from information from grype-db? that would be ideal...
	var versionSegments []int
	if d.Version != nil {
		versionSegments = d.Version.Segments()
	}

	if len(versionSegments) > 0 {
		switch d.Type {
		// derived from https://github.com/anchore/anchore-engine/blob/5bbbe6b9744f2fb806198ae5d6f0cfe3b367fd9d/anchore_engine/services/policy_engine/__init__.py#L149-L159
		case distro.CentOS, distro.RedHat, distro.Fedora:
			// TODO: there is no mapping of fedora version to RHEL latest version (only the name)
			return fmt.Sprintf("rhel:%d", versionSegments[0])
		case distro.AmazonLinux:
			return fmt.Sprintf("amzn:%d", versionSegments[0])
		case distro.OracleLinux:
			return fmt.Sprintf("ol:%d", versionSegments[0])
		case distro.Alpine:
			// XXX this assumes that a major and minor versions will always exist in Segments
			return fmt.Sprintf("alpine:%d.%d", versionSegments[0], versionSegments[1])
		}
	}
	return fmt.Sprintf("%s:%s", strings.ToLower(d.Type.String()), d.FullVersion())
}

func languageNamespaces(l syftPkg.Language) map[string]namer {
	namespaces := make(map[string]namer)
	// TODO: can we drive this from information from grype-db? that would be ideal...
	switch l {
	case syftPkg.Ruby:
		namespaces["github:gem"] = defaultNamer
	case syftPkg.Java:
		namespaces["github:java"] = githubJavaNamer
	case syftPkg.JavaScript:
		namespaces["github:npm"] = defaultNamer
	case syftPkg.Python:
		namespaces["github:python"] = defaultNamer
	}
	return namespaces
}

func cpeNamespaces() []string {
	return []string{"nvd"}
}
